package com.example.auth.service.impl;

import com.example.auth.dto.ProjectDTO;
import com.example.auth.dto.TaskDTO;
import com.example.auth.dto.TaskEvaluationDTO;
import com.example.auth.entity.Task;
import com.example.auth.entity.TaskEvaluation;
import com.example.auth.entity.User;
import com.example.auth.repository.TaskEvaluationRepository;
import com.example.auth.repository.TaskRepository;
import com.example.auth.service.TaskEvaluationService;
import com.example.auth.service.TaskService;
import com.example.auth.service.UserService;
import com.example.auth.service.ProjectService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;

/**
 * Task evaluation service implementation class
 */
@Service
public class TaskEvaluationServiceImpl implements TaskEvaluationService {

    private static final Logger logger = LoggerFactory.getLogger(TaskEvaluationServiceImpl.class);

    @Autowired
    private TaskEvaluationRepository taskEvaluationRepository;

    @Autowired
    private TaskRepository taskRepository;

    @Autowired
    private TaskService taskService;

    @Autowired
    private UserService userService;

    @Autowired
    private ProjectService projectService;

    @Override
    @Transactional
    public TaskEvaluationDTO createOrUpdateEvaluation(Long taskId, Integer score, String comment, Long evaluatedBy) {
        logger.info("Creating or updating task evaluation, Task ID: {}, Score: {}, Evaluated By ID: {}", taskId, score, evaluatedBy);

        // Find existing evaluation
        Optional<TaskEvaluation> existingEvaluation = taskEvaluationRepository.findByTaskId(taskId);

        TaskEvaluation evaluation;
        if (existingEvaluation.isPresent()) {
            // Update existing evaluation
            logger.info("Updating existing evaluation, Evaluation ID: {}", existingEvaluation.get().getId());
            evaluation = existingEvaluation.get();
            evaluation.setScore(score);
            evaluation.setComment(comment);
        } else {
            // Create new evaluation
            logger.info("Creating new evaluation");
            evaluation = new TaskEvaluation();
            evaluation.setTaskId(taskId);
            evaluation.setScore(score);
            evaluation.setComment(comment);
            evaluation.setEvaluatedBy(evaluatedBy);
        }

        // Save evaluation
        evaluation = taskEvaluationRepository.save(evaluation);
        logger.info("Evaluation saved successfully, Evaluation ID: {}", evaluation.getId());

        // Task is already marked as completed when submitted, no need to change task status here
        Optional<Task> taskOpt = taskRepository.findById(taskId);
        if (taskOpt.isPresent()) {
            Task task = taskOpt.get();
            // Check if the task belongs to a project
            if (task.getProjectId() != null) {
                try {
                    // Check if all tasks in the project have been evaluated
                    boolean allTasksEvaluated = taskRepository.findByProjectId(task.getProjectId()).stream()
                            .allMatch(t -> taskEvaluationRepository.findByTaskId(t.getId()).isPresent());
                    
                    // If all tasks have been evaluated, update project status to "Completed"
                    if (allTasksEvaluated) {
                        logger.info("All tasks in project have been evaluated, updating project status to Completed, Project ID: {}", task.getProjectId());
                        projectService.updateProjectStatus(task.getProjectId(), "Completed");
                    }
                } catch (Exception e) {
                    logger.warn("Failed to update project status after task evaluation: {}", e.getMessage());
                }
            }
        } else {
            logger.warn("Task not found for evaluation, Task ID: {}", taskId);
        }

        // Get task and evaluator information for DTO creation
        TaskDTO task = taskService.getTaskById(taskId);
        User evaluator = userService.findById(evaluatedBy);
        String evaluatorName = evaluator != null ? evaluator.getUsername() : "Unknown User";

        return TaskEvaluationDTO.fromEntity(evaluation, task.getTitle(), evaluatorName);
    }

    @Override
    public TaskEvaluationDTO getEvaluationByTaskId(Long taskId) {
        logger.info("Getting task evaluation, Task ID: {}", taskId);

        Optional<TaskEvaluation> evaluation = taskEvaluationRepository.findByTaskId(taskId);

        if (evaluation.isEmpty()) {
            logger.info("Task evaluation does not exist, Task ID: {}", taskId);
            return null;
        }

        // Get task and evaluator information
        TaskDTO task = taskService.getTaskById(taskId);
        User evaluator = userService.findById(evaluation.get().getEvaluatedBy());
        String evaluatorName = evaluator != null ? evaluator.getUsername() : "Unknown User";

        logger.info("Successfully retrieved task evaluation, Evaluation ID: {}", evaluation.get().getId());
        return TaskEvaluationDTO.fromEntity(evaluation.get(), task.getTitle(), evaluatorName);
    }

    @Override
    @Transactional
    public boolean deleteEvaluation(Long taskId) {
        logger.info("Deleting task evaluation, Task ID: {}", taskId);

        Optional<TaskEvaluation> evaluation = taskEvaluationRepository.findByTaskId(taskId);

        if (evaluation.isEmpty()) {
            logger.info("Task evaluation does not exist, cannot delete, Task ID: {}", taskId);
            return false;
        }

        // Deleting the evaluation does not change the task completion status, as task status is determined by file submission
        Optional<Task> taskOpt = taskRepository.findById(taskId);
        if (taskOpt.isPresent()) {
            Task task = taskOpt.get();
            // If the task belongs to a project, project status may need to be updated
            if (task.getProjectId() != null) {
                try {
                    // Check project status, if project is in Completed status, update to "Waiting for Review"
                    ProjectDTO project = projectService.getProjectById(task.getProjectId());
                    if ("Completed".equals(project.getStatus())) {
                        logger.info("Updating project status to Waiting for Review after evaluation deletion, Project ID: {}", task.getProjectId());
                        projectService.updateProjectStatus(task.getProjectId(), "Waiting for Review");
                    }
                } catch (Exception e) {
                    logger.warn("Failed to update project status after evaluation deletion: {}", e.getMessage());
                }
            }
        }

        taskEvaluationRepository.delete(evaluation.get());
        logger.info("Task evaluation deleted successfully, Evaluation ID: {}", evaluation.get().getId());
        return true;
    }
}